1 Setup

This section and the next are relevant for reproducibility purposes. For results, please skip to section 3 (Quality Control)

  • Libraries
suppressPackageStartupMessages({
  library(data.table)
  library(DESeq2)
  library(gplots)
  library(here)
  library(hyperSpec)
  library(magrittr)
  library(parallel)
  library(pheatmap)
  library(plotly)
  library(pvclust)
  library(tidyverse)
  library(tximport)
  library(vsn)
  library(emoji)
})
  • Helper functions
source(here("UPSCb-common/src/R/featureSelection.R"))
  • Graphics
hpal <- colorRampPalette(c("blue","white","red"))(100)

2 Data

  • Sample information
samples <- read_csv(here("data/drought_roots.csv"),
                      col_types=cols(.default=col_factor()))
  • tx2gene translation table
tx2gene <- suppressMessages(read_delim(here("reference/annotation/Picab02_tx2gene.tsv.gz"), delim="\t", col_names=c("TXID","GENE"), skip=1))
  • Raw data
filelist <- list.files(here("results/Salmon"), 
                          recursive = TRUE, 
                          pattern = "quant.sf",
                          full.names = TRUE)
  • Sanity check to ensure that the data is sorted according to the sample info
stopifnot(all(match(sub("[1-3]_151118_BC852HANXX_P2503_", "", sub("*_sortmerna_trimmomatic","",basename(dirname(filelist)))),
                    samples$SciLifeID) == 1:nrow(samples)))

samples_rep <-rbind(samples,samples)
samples_rep <- rbind(samples_rep,samples)
  • Add filelist to samples as a new column
samples_rep %<>% mutate(Filenames = filelist)
  • Export full rank samples
write_tsv(samples_rep,here("data/samples_full_rank.txt"))
  • Read the expression at the gene level
txi <- suppressMessages(tximport(files = samples_rep$Filenames,
                                 type = "salmon",
                                 tx2gene=tx2gene))
counts <- txi$counts
samples_rep$Filenames <- sub("*_151118_BC852HANXX_P2503_", "_", sub("*_sortmerna_trimmomatic","",basename(dirname(samples_rep$Filenames))))
colnames(counts) <- samples_rep$Filenames
counts <- as.data.frame(counts)
  • Import the list of the genes expressed in the control and C2d condition to avoid bias
expr_genes <- read.table(here("data/analysis/expressed_genes.txt"))
colnames(expr_genes) <- "Genes"
counts <- filter(counts, rownames(counts) %in% expr_genes$Genes)

 

3 Quality Control

3.1 “Not expressed” genes

sel <- rowSums(counts) == 0
sprintf("%s%% percent (%s) of %s genes are not expressed",
        round(sum(sel) * 100/ nrow(counts),digits=1),
        sum(sel),
        nrow(counts))
## [1] "0% percent (0) of 31935 genes are not expressed"

3.2 Sequencing depth

  • Let us take a look at the sequencing depth, colouring by Level
dat <- tibble(x=colnames(counts),y=colSums(counts)) %>% 
  bind_cols(samples_rep)

ggplot(dat,aes(x,y,fill=Level)) + 
  geom_col() + 
  scale_y_continuous(name="reads") +
  facet_grid(~ factor(Level), scales = "free") +
  theme_bw() + 
  theme(axis.text.x=element_text(angle=90,size=4), axis.title.x=element_blank()) +
  labs(title ="Sample sequencing depth")

👉 We observe some variation in the raw sequencing depth between conditions

3.3 Per-gene mean expression

i.e. the mean raw count of every gene across samples is calculated and displayed on a log10 scale.

ggplot(data.frame(value=log10(rowMeans(counts))),aes(x=value)) + 
  geom_density(na.rm = TRUE) +
  ggtitle("Gene mean raw counts distribution") +
  scale_x_continuous(name="mean raw counts (log10)") + 
  theme_bw()

👉 The gene mean raw counts distribution is as expected since the highest peak is around 2

3.4 Per-sample expression

dat <- as.data.frame(log10(counts)) %>% 
  utils::stack() %>% 
  mutate(Level=samples_rep$Level[match(ind,samples_rep$Filenames)]) 


ggplot(dat,aes(x=values,group=ind,col=Level)) + 
  geom_density(na.rm = TRUE) + 
  ggtitle("Sample raw counts distribution") +
  scale_x_continuous(name="per gene raw counts (log10)") + 
  theme_bw()

👉 All samples have the same sequencing depth characteristics and there is no deviation when we look at one or the other condition

  • Export raw expression data
dir.create(here("data/analysis/salmon"),showWarnings=FALSE,recursive=TRUE)
write.csv(counts,file=here("data/analysis/salmon/raw-unormalised-gene-expression_data_expressed.csv"))

 

4 Data normalisation

4.1 Preparation

For visualization, the data is submitted to a variance stabilization transformation using DESeq2. The dispersion is estimated independently of the sample condition and replicate.

dds <- DESeqDataSetFromTximport(
  txi=txi,
  colData = samples_rep,
  design = ~ Level)
##   Note: levels of factors in the design contain characters other than
##   letters, numbers, '_' and '.'. It is recommended (but not required) to use
##   only letters, numbers, and delimiters '_' or '.', as these are safe characters
##   for column names in R. [This is a message, not a warning or an error]
## using counts and average transcript lengths from tximport
dds <- dds[rownames(dds) %in% expr_genes$Genes,]

4.2 Size factors

(i.e. the sequencing library size effect)

dds <- estimateSizeFactors(dds) %>%   
  suppressMessages()

boxplot of the sequencing libraries size factor:

boxplot(normalizationFactors(dds),
        main="Sequencing libraries size factor",
        las=2,log="y")
abline(h=1, col = "Red", lty = 3)

and without outliers:

boxplot(normalizationFactors(dds),
        main="Sequencing libraries size factor",
        las=2,log="y", outline=FALSE)
abline(h=1, col = "Red", lty = 3)

👉 The sequencing libraries size factor is highly variable across samples but similar for the technical replicates

4.3 Validation

Let’s look at standard deviations before and after VST normalization. This plot is to see whether there is a dependency of SD on the mean.

Before:

meanSdPlot(log1p(counts(dds))[rowSums(counts(dds))>0,])

After VST normalization, the red line should be almost horizontal which indicates no dependency of variance on mean (homoscedastic).

4.4 Variance Stabilizing Transformation

vsd <- varianceStabilizingTransformation(dds, blind=TRUE)
vst <- assay(vsd)
vst <- vst - min(vst)

meanSdPlot(vst[rowSums(vst)>0,])

👉 We can conclude that the variance stabilization worked adequately even if the red line is not perfectly horizontal


 

4.5 QC on the normalised data

4.5.1 PCA

pc <- prcomp(t(vst))
percent <- round(summary(pc)$importance[2,]*100)

4.5.2 Scree plot

We define the number of variables of the model (=1) and the number of possible combinations (=8).

We plot the percentage explained by different components

  • the red line represents number of variables in the model
  • the orange line represents number of variable combinations.
nvar=1
nlevel=nlevels(dds$Level)
ggplot(tibble(x=1:length(percent),y=cumsum(percent)),aes(x=x,y=y)) +
  geom_line() + scale_y_continuous("variance explained (%)",limits=c(0,100)) +
  scale_x_continuous("Principal component") + 
  geom_vline(xintercept=nvar,colour="red",linetype="dashed",linewidth=0.5) + 
  geom_hline(yintercept=cumsum(percent)[nvar],colour="red",linetype="dashed",linewidth=0.5) +
  geom_vline(xintercept=nlevel,colour="orange",linetype="dashed",linewidth=0.5) + 
  geom_hline(yintercept=cumsum(percent)[nlevel],colour="orange",linetype="dashed",linewidth=0.5)+
  ggtitle("Percentage of variance explained by different components")

4.5.3 PCA plot

pc.dat <- bind_cols(PC1=pc$x[,1],
                    PC2=pc$x[,2],
                    as.data.frame(colData(dds)))

p <- ggplot(pc.dat,aes(x=PC1,y=PC2,col=Level,shape=Level,text=Filenames)) + 
  geom_point(size=2) + 
  ggtitle("Principal Component Analysis",subtitle="variance stabilized counts")

ggplotly(p) %>% 
  layout(xaxis=list(title=paste("PC1 (",percent[1],"%)",sep="")),
         yaxis=list(title=paste("PC2 (",percent[2],"%)",sep="")))
## Warning: The shape palette can deal with a maximum of 6 discrete values because
## more than 6 becomes difficult to discriminate; you have 8. Consider
## specifying shapes manually if you must have them.

👉 Some conditions clusterized better than others in the PCA plot

4.6 Sequencing depth

Number of genes expressed per condition at different cutoffs:

conds <- factor(dds$Level)

dev.null <- rangeSamplesSummary(counts=vst,
                                conditions=conds,
                                nrep=3)

4.7 Heatmap

Filter for noise

sels <- rangeFeatureSelect(counts=vst,
                           conditions=conds,
                           nrep=3) %>% 
  suppressWarnings()

vst.cutoff <- 2
abline(h=10000, col="Red", lty=3)

  • Set the cut off to 5 in order to retrieve less than 10 000 genes
vst.cutoff <- 5

hm_reduced <- heatmap.2(t(scale(t(vst[sels[[vst.cutoff+1]],]))),
                distfun=pearson.dist,
                hclustfun=function(X){hclust(X,method="ward.D2")},
                labRow = NA,trace = "none",
                labCol = conds,
                col=hpal)

plot(as.hclust(hm_reduced$colDendrogram),xlab="",sub="", cex.axis=2)

  • Using pheatmap
mat <- t(scale(t(vst[sels[[vst.cutoff+1]],])))
hm <- pheatmap(mat,
               color = hpal,
               border_color = NA,
               clustering_distance_rows = "correlation",
               clustering_method = "ward.D2",
               show_rownames = F,
               labels_col = conds,
               angle_col = 90,
               legend = F)

plot(as.hclust(hm_reduced$colDendrogram),xlab="",sub="", cex.axis=2)

👉 The different conditions are not so different in gene expression level

4.8 Clustering of samples

Done to assess the previous dendrogram’s reproducibility

hm.pvclust <- pvclust(data = t(scale(t(vst[sels[[vst.cutoff+1]],]))),
                       method.hclust = "ward.D2", 
                       nboot = 1000, parallel = TRUE)
## Creating a temporary cluster...done:
## socket cluster with 15 nodes on host 'localhost'
## Multiscale bootstrap... Done.

Plot the clustering with bp and au

plot(hm.pvclust, labels = conds, cex.axis=1.5)
pvrect(hm.pvclust)

👉 Some conditions clusterize better than others

bootstrapping results as a table
print(hm.pvclust, digits=3)
## 
## Cluster method: ward.D2
## Distance      : correlation
## 
## Estimates on edges:
## 
##       si    au    bp se.si se.au se.bp      v      c  pchi
## 1  0.433 0.724 0.702 0.038 0.027 0.005 -0.563  0.031 0.948
## 2  1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 3  0.744 0.879 0.850 0.030 0.018 0.004 -1.103  0.066 0.149
## 4  1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 5  0.115 0.625 0.474 0.039 0.029 0.005 -0.126  0.192 0.521
## 6  1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 7  0.754 0.889 0.835 0.028 0.017 0.004 -1.099  0.124 0.069
## 8  1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 9  0.065 0.589 0.469 0.038 0.030 0.005 -0.073  0.152 0.625
## 10 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 11 0.944 0.970 0.979 0.018 0.011 0.002 -1.957 -0.071 0.387
## 12 0.502 0.786 0.670 0.037 0.023 0.005 -0.616  0.176 0.345
## 13 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 14 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 15 0.866 0.943 0.887 0.021 0.011 0.003 -1.394  0.185 0.499
## 16 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 17 0.706 0.861 0.828 0.031 0.020 0.004 -1.016  0.069 0.698
## 18 0.139 0.644 0.473 0.040 0.029 0.005 -0.150  0.219 0.484
## 19 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 20 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 21 0.558 0.791 0.751 0.036 0.024 0.005 -0.743  0.065 0.799
## 22 0.312 0.685 0.607 0.039 0.028 0.005 -0.376  0.105 0.477
## 23 0.182 0.621 0.550 0.038 0.029 0.005 -0.216  0.091 0.866
## 24 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 25 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 26 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 27 0.226 0.642 0.570 0.038 0.029 0.005 -0.269  0.094 0.007
## 28 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 29 0.196 0.643 0.534 0.039 0.029 0.005 -0.226  0.140 0.600
## 30 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 31 0.829 0.926 0.866 0.024 0.013 0.004 -1.276  0.170 0.383
## 32 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 33 0.109 0.639 0.450 0.041 0.029 0.005 -0.115  0.240 0.509
## 34 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 35 0.888 0.952 0.902 0.019 0.010 0.003 -1.481  0.186 0.311
## 36 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 37 0.700 0.869 0.790 0.031 0.018 0.004 -0.964  0.157 0.480
## 38 0.000 0.527 0.389 0.000 0.031 0.005  0.106  0.175 0.242
## 39 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 40 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 41 0.639 0.833 0.782 0.033 0.021 0.004 -0.872  0.095 0.024
## 42 0.149 0.576 0.573 0.036 0.030 0.005 -0.188  0.004 0.286
## 43 0.349 0.701 0.626 0.038 0.027 0.005 -0.425  0.103 0.683
## 44 0.267 0.651 0.605 0.038 0.029 0.005 -0.328  0.062 0.982
## 45 0.973 0.988 0.974 0.009 0.005 0.002 -2.100  0.160 0.237
## 46 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 47 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 48 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 49 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 50 0.753 0.897 0.801 0.028 0.015 0.004 -1.055  0.211 0.852
## 51 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 52 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 53 0.157 0.594 0.558 0.037 0.030 0.005 -0.191  0.046 0.475
## 54 0.506 0.784 0.683 0.037 0.023 0.005 -0.630  0.155 0.568
## 55 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 56 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 57 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 58 0.038 0.504 0.535 0.033 0.031 0.005 -0.049 -0.040 0.550
## 59 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 60 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 61 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 62 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 63 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 64 0.786 0.894 0.888 0.029 0.018 0.003 -1.232  0.018 0.994
## 65 0.983 0.991 0.994 0.010 0.006 0.001 -2.453 -0.089 0.097
## 66 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 67 0.815 0.905 0.917 0.028 0.018 0.003 -1.348 -0.038 0.424
## 68 0.971 0.983 0.995 0.018 0.012 0.001 -2.344 -0.220 0.097
## 69 0.931 0.954 0.995 0.040 0.030 0.001 -2.131 -0.450 0.123
## 70 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 71 0.721 0.893 0.743 0.029 0.015 0.005 -0.947  0.296 0.180
## 72 0.531 0.850 0.539 0.037 0.018 0.005 -0.568  0.470 0.203
## 73 0.410 0.819 0.462 0.042 0.021 0.005 -0.407  0.503 0.456
## 74 0.036 0.786 0.230 0.062 0.026 0.004 -0.027  0.766 0.819
## 75 0.080 0.680 0.377 0.045 0.028 0.005 -0.077  0.391 0.782
## 76 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 77 0.368 0.734 0.588 0.039 0.025 0.005 -0.424  0.201 0.745
## 78 0.177 0.799 0.292 0.054 0.024 0.005 -0.145  0.693 0.771
## 79 0.094 0.726 0.333 0.049 0.027 0.005 -0.083  0.516 0.626
## 80 0.094 0.726 0.333 0.049 0.027 0.005 -0.083  0.516 0.626
## 81 0.094 0.726 0.333 0.049 0.027 0.005 -0.083  0.516 0.626
## 82 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000
## 83 1.000 1.000 1.000 0.000 0.000 0.000  0.000  0.000 0.000

5 Combine technical replicates

samples_rep$Filenames <- filelist
samples_rep$BioID <- sub("[1-3]_151118_BC852HANXX_", "", sub("*_sortmerna_trimmomatic","",basename(dirname(samples_rep$Filenames))))

Merging technical replicates

txi$counts <- sapply(split.data.frame(t(txi$counts),samples_rep$BioID),colSums)
txi$length <- sapply(split.data.frame(t(txi$length),samples_rep$BioID),colMaxs)

Counts are now in alphabetic order, check and reorder if necessary

stopifnot(colnames(txi$counts) == samples_rep$BioID)
samples_rep <- samples_rep[match(colnames(txi$counts),samples_rep$BioID),]

Recreate the dds

dds <- DESeqDataSetFromTximport(
        txi=txi,
       colData = samples_rep,
       design = ~ Level)
##   Note: levels of factors in the design contain characters other than
##   letters, numbers, '_' and '.'. It is recommended (but not required) to use
##   only letters, numbers, and delimiters '_' or '.', as these are safe characters
##   for column names in R. [This is a message, not a warning or an error]
## using counts and average transcript lengths from tximport
dds <- dds[rownames(dds) %in% expr_genes$Genes,]

save(dds,file=here("data/analysis/salmon/dds_merge_expr_genes.rda"))

 

6 Summary

The data are quite good so we can continue with our analysis

7 Session Info

Session Info
sessionInfo()
## R version 4.2.1 (2022-06-23)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 18.04.6 LTS
## 
## Matrix products: default
## BLAS/LAPACK: /usr/lib/x86_64-linux-gnu/libopenblasp-r0.2.20.so
## 
## locale:
##  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
##  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
##  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
##  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
##  [9] LC_ADDRESS=C               LC_TELEPHONE=C            
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       
## 
## attached base packages:
##  [1] parallel  grid      stats4    stats     graphics  grDevices utils    
##  [8] datasets  methods   base     
## 
## other attached packages:
##  [1] emoji_15.0                  vsn_3.64.0                 
##  [3] tximport_1.24.0             forcats_0.5.2              
##  [5] stringr_1.5.0               dplyr_1.0.10               
##  [7] purrr_1.0.1                 readr_2.1.3                
##  [9] tidyr_1.2.1                 tibble_3.1.8               
## [11] tidyverse_1.3.2             pvclust_2.2-0              
## [13] plotly_4.10.1               pheatmap_1.0.12            
## [15] magrittr_2.0.3              hyperSpec_0.100.0          
## [17] xml2_1.3.3                  ggplot2_3.4.0              
## [19] lattice_0.20-45             here_1.0.1                 
## [21] gplots_3.1.3                DESeq2_1.36.0              
## [23] SummarizedExperiment_1.28.0 Biobase_2.58.0             
## [25] MatrixGenerics_1.10.0       matrixStats_0.63.0         
## [27] GenomicRanges_1.50.1        GenomeInfoDb_1.34.4        
## [29] IRanges_2.32.0              S4Vectors_0.36.1           
## [31] BiocGenerics_0.44.0         data.table_1.14.6          
## 
## loaded via a namespace (and not attached):
##   [1] readxl_1.4.1           backports_1.4.1        lazyeval_0.2.2        
##   [4] splines_4.2.0          crosstalk_1.2.0        BiocParallel_1.32.4   
##   [7] digest_0.6.31          htmltools_0.5.4        fansi_1.0.3           
##  [10] memoise_2.0.1          googlesheets4_1.0.1    limma_3.52.4          
##  [13] tzdb_0.3.0             Biostrings_2.66.0      annotate_1.74.0       
##  [16] modelr_0.1.10          vroom_1.6.0            timechange_0.1.1      
##  [19] jpeg_0.1-10            colorspace_2.0-3       blob_1.2.3            
##  [22] rvest_1.0.3            haven_2.5.1            xfun_0.35             
##  [25] hexbin_1.28.2          crayon_1.5.2           RCurl_1.98-1.9        
##  [28] jsonlite_1.8.4         genefilter_1.78.0      survival_3.4-0        
##  [31] glue_1.6.2             gtable_0.3.1           gargle_1.2.1          
##  [34] zlibbioc_1.44.0        XVector_0.38.0         DelayedArray_0.24.0   
##  [37] scales_1.2.1           DBI_1.1.3              Rcpp_1.0.9            
##  [40] viridisLite_0.4.1      xtable_1.8-4           bit_4.0.5             
##  [43] preprocessCore_1.58.0  htmlwidgets_1.6.1      httr_1.4.4            
##  [46] RColorBrewer_1.1-3     ellipsis_0.3.2         farver_2.1.1          
##  [49] pkgconfig_2.0.3        XML_3.99-0.13          sass_0.4.4            
##  [52] dbplyr_2.2.1           deldir_1.0-6           locfit_1.5-9.7        
##  [55] utf8_1.2.2             labeling_0.4.2         tidyselect_1.2.0      
##  [58] rlang_1.0.6            AnnotationDbi_1.60.0   munsell_0.5.0         
##  [61] cellranger_1.1.0       tools_4.2.0            cachem_1.0.6          
##  [64] cli_3.6.0              generics_0.1.3         RSQLite_2.2.20        
##  [67] broom_1.0.2            evaluate_0.19          fastmap_1.1.0         
##  [70] yaml_2.3.6             knitr_1.41             bit64_4.0.5           
##  [73] fs_1.5.2               caTools_1.18.2         KEGGREST_1.38.0       
##  [76] brio_1.1.3             compiler_4.2.0         rstudioapi_0.14       
##  [79] png_0.1-8              testthat_3.1.6         affyio_1.66.0         
##  [82] reprex_2.0.2           geneplotter_1.74.0     bslib_0.4.2           
##  [85] stringi_1.7.12         highr_0.10             Matrix_1.5-3          
##  [88] vctrs_0.5.1            pillar_1.8.1           lifecycle_1.0.3       
##  [91] BiocManager_1.30.19    jquerylib_0.1.4        bitops_1.0-7          
##  [94] R6_2.5.1               latticeExtra_0.6-30    affy_1.74.0           
##  [97] KernSmooth_2.23-20     codetools_0.2-18       gtools_3.9.4          
## [100] assertthat_0.2.1       rprojroot_2.0.3        withr_2.5.0           
## [103] GenomeInfoDbData_1.2.9 hms_1.1.2              rmarkdown_2.19        
## [106] googledrive_2.0.0      lubridate_1.9.0        interp_1.1-3